/* Copyright (c) 2025 Beijing Semidrive Technology Corporation
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @file  EthDesc.c
 * @brief Semidrive. AUTOSAR 4.3.1 MCAL Eth plugins.
 */
#ifdef __cplusplus
extern "C" {
#endif

#include "EthDesc.h"
#include "Std_Types.h"
#include "Mcal_MemLibc.h"
#include "Mcal_Cache.h"

// Define the start of a section of variables that are not initialized
#define ETH_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

// Declare a variable of type locked_desc_ring_t with the name Eth_Buf_Confirm
// This variable is an array with dimensions ETH_MAXCTRLS_SUPPORTED, ETH_MAX_DMA_CHANNEL and DESC_TYPE_MAX
VAR(locked_desc_ring_t, ETH_VAR)        Eth_Buf_Confirm\
[ETH_MAXCTRLS_SUPPORTED]\
[ETH_MAX_DMA_CHANNEL][DESC_TYPE_MAX];

// Define the end of a section of variables that are not initialized
#define ETH_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Eth_MemMap.h"

// Check if ETH_NO_CACHEABLE_NEEDED is defined and equal to STD_ON
#if (ETH_NO_CACHEABLE_NEEDED == STD_ON)
// Define the start of a section of variables that are not initialized and not cacheable
#define ETH_START_SEC_VAR_NO_INIT_NO_CACHE_UNSPECIFIED
#else
// Define the start of a section of variables that are not initialized
#define ETH_START_SEC_VAR_NO_INIT_UNSPECIFIED
#endif
#include "Eth_MemMap.h"

// Declare a variable of type dma_desc_ring_t with the name Eth_Desc_Buf
// This variable is an array with dimensions ETH_MAXCTRLS_SUPPORTED, ETH_MAX_DMA_CHANNEL and DESC_TYPE_MAX
// The variable is aligned to a cache line
VAR_ALIGN(dma_desc_ring_t Eth_Desc_Buf \
          [ETH_MAXCTRLS_SUPPORTED]\
          [ETH_MAX_DMA_CHANNEL][DESC_TYPE_MAX], \
          CACHE_LINE);

#if (ETH_DIRECT_FORWARD_ENABLE == STD_ON)
VAR_ALIGN(dma_desc_ring_t Eth_Desc_Buf_Rx_Backup \
          [ETH_DIRECT_FORWARD_NUM], \
          CACHE_LINE);
#endif

// Check if ETH_NO_CACHEABLE_NEEDED is defined and equal to STD_ON
#if (ETH_NO_CACHEABLE_NEEDED == STD_ON)
    // Define the end of a section of variables that are not initialized and not cacheable
#define ETH_STOP_SEC_VAR_NO_INIT_NO_CACHE_UNSPECIFIED
#else
    // Define the end of a section of variables that are not initialized
#define ETH_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#endif
#include "Eth_MemMap.h"

// Define the start of a section of code
#define ETH_START_SEC_CODE
#include "Eth_MemMap.h"

/**
 * @description:
 * @param {ring_t} *ring
 * @param {uint32} sizepower
 * @return {*}
 */
static void ring_clr(ring_t *ring, uint32 sizepower)
{
    ring->size = (uint32)(0x01u << sizepower);
    ring->front = ring->rear = 0u;
}

/*
    DMA DESC ring apis wrapper
*/
/**
 * @brief Clears the descriptor rings for an Ethernet controller.
 *
 * This function clears the descriptor rings (both transmit and receive) for all DMA channels of an
 * Ethernet controller. It initializes the descriptors to a known state (typically zeros) and resets
 * the ring control blocks (ringcb) to an empty state. This operation is useful when reinitializing
 * the Ethernet controller or preparing it for a new set of DMA operations.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller for which to clear the descriptor rings.
 *
 * @note The function assumes that the `Eth_Desc_Buf` array is defined and accessible, and that it
 *       contains the descriptor rings and control blocks for each controller, channel, and direction.
 *
 * @note The function uses the `mini_memclr_s` function (or similar) to clear the descriptors to a known
 *       state. Depending on the system configuration, it may also use the `Mcal_CleanCache`
 *       function (or similar) to ensure that any cached versions of the descriptors are invalidated.
 *
 * @note The function calls the `ring_clr` function (or similar) to reset the ring control blocks to an
 *       empty state.
 *
 * @warning The caller must ensure that the `CtrlIdx` parameter is a valid index of an initialized
 *          Ethernet controller. Accessing an invalid `CtrlIdx` could lead to undefined behavior.
 */
static void desc_ring_clr(uint8 CtrlIdx)
{
    ring_t *ring;
    dma_desc_ring_t *desc_ring;

    /*PRQA S 2877 2*/
    for (uint8 ch = 0; ch < ETH_MAX_DMA_CHANNEL; ch++) {

        desc_ring = &Eth_Desc_Buf[CtrlIdx][ch][DESC_TX];
        // do this to not rely on c evn clean bss and clean cache.
        Mcal_MemClr(desc_ring->desc,sizeof(desc_ring->desc));
#if (ETH_NO_CACHEABLE_NEEDED == STD_OFF)
        Mcal_CleanCache((uint32)desc_ring->desc,sizeof(desc_ring->desc));
#endif
        ring = &desc_ring->ringcb;
        ring_clr(ring, MAX_RING_SIZE_POWER);


        desc_ring = &Eth_Desc_Buf[CtrlIdx][ch][DESC_RX];
        // do this to not rely on c evn clean bss and clean cache.
        Mcal_MemClr(desc_ring->desc,sizeof(desc_ring->desc));
#if (ETH_NO_CACHEABLE_NEEDED == STD_OFF)
        Mcal_CleanCache((uint32)desc_ring->desc,sizeof(desc_ring->desc));
#endif
        ring = &desc_ring->ringcb;
        ring_clr(ring, MAX_RING_SIZE_POWER);
    }
}
/**
 * @brief Clears the locked descriptor rings for an Ethernet controller.
 *
 * This function clears the locked descriptor rings (both transmit and receive) for all DMA channels of
 * an Ethernet controller. It resets the ring control blocks (ringcb) of the locked descriptor rings
 * to an empty state. Locked descriptor rings are typically used to keep track of buffers that have
 * been processed by the DMA engine but not yet acknowledged or freed by the upper layers. Clearing
 * these rings can be useful when reinitializing the Ethernet controller or recovering from errors.
 *
 * @param CtrlIdx The index or identifier of the Ethernet controller for which to clear the locked
 *                descriptor rings.
 *
 * @note The function assumes that the `Eth_Buf_Confirm` array is defined and accessible, and that it
 *       contains the locked descriptor rings and control blocks for each controller, channel, and
 *       direction.
 *
 * @note The function calls the `ring_clr` function (or similar) to reset the ring control blocks of
 *       the locked descriptor rings to an empty state.
 *
 * @warning The caller must ensure that the `CtrlIdx` parameter is a valid index of an initialized
 *          Ethernet controller. Accessing an invalid `CtrlIdx` could lead to undefined behavior.
 */
static void locked_desc_clr(uint8 CtrlIdx)
{
    ring_t *ring;
    locked_desc_ring_t *locked_ring;

    /*PRQA S 2877 2*/
    for (uint8 ch = 0; ch < ETH_MAX_DMA_CHANNEL; ch++) {

        locked_ring = &Eth_Buf_Confirm[CtrlIdx][ch][DESC_RX];
        ring = &locked_ring->ringcb;
        ring_clr(ring, MAX_RING_SIZE_POWER);

        locked_ring = &Eth_Buf_Confirm[CtrlIdx][ch][DESC_TX];
        ring = &locked_ring->ringcb;
        ring_clr(ring, MAX_RING_SIZE_POWER);
    }
}
/**
 * @description: desc ring init
 * @param {uint8} CtrlIdx
 * @return {*}
 */
void desc_ring_init(uint8 CtrlIdx)
{
    desc_ring_clr(CtrlIdx);
    locked_desc_clr(CtrlIdx);
}
#define ETH_STOP_SEC_CODE
#include "Eth_MemMap.h"

#define ETH_START_SEC_CODE_FAST
#include "Eth_MemMap.h"
/**
 * @description:
 * @param {ring_t} *ring
 * @return {*}
 */
static uint32 ring_remain(ring_t *ring)
{
    return (uint32)(ring->size + ring->front - ring->rear);
}
/**
 * @description:
 * @param {ring_t} *ring
 * @return {*}
 */
static uint32 ring_used(ring_t *ring)
{
    return (uint32)(ring->rear - ring->front);
}
/**
 * @description:
 * @param {ring_t} *ring
 * @return {*}
 */
static sint32 ring_get_next_index(ring_t *ring)
{
    if (ring_used(ring)) {
        return (uint32)(ring->front % ring->size);
    }

    return -1;
}
/**
 * @brief Allocates a contiguous block of DMA descriptors from a descriptor ring.
 *
 * This function allocates a specified number of contiguous DMA descriptors from the transmit or receive
 * descriptor ring of an Ethernet controller. It updates the ring's rear pointer to reflect the newly
 * allocated descriptors. The function ensures that the requested number of descriptors is available
 * before allocating them, and it uses critical sections to ensure thread safety when updating the ring
 * state.
 *
 * @param desc_ring A pointer to the descriptor ring from which to allocate descriptors.
 * @param cnt The number of descriptors to allocate.
 *
 * @return A pointer to the first descriptor in the allocated block, or `NULL_PTR` if the requested
 *         number of descriptors is not available.
 *
 * @note The function assumes that the `desc_ring` parameter points to a valid descriptor ring that is
 *       part of an initialized Ethernet controller.
 *
 * @note The function uses the `ring_remain` function (or similar) to check if the requested number of
 *       descriptors is available in the ring.
 *
 * @note The function updates the ring's `rear` pointer to reflect the newly allocated descriptors. It
 *       wraps around the ring if necessary.
 *
 * @note The function uses critical sections (via `SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_00` and
 *       `SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_00` or similar functions) to ensure thread safety when
 *       accessing and modifying the ring state.
 *
 * @warning The caller must ensure that the `cnt` parameter is a valid number of descriptors and does
 *          not exceed the size of the descriptor ring. Attempting to allocate more descriptors than
 *          are available could lead to undefined behavior.
 */
static struct dma_desc *dma_desc_ring_alloc(dma_desc_ring_t *desc_ring, uint32 cnt)
{

    ring_t *ring = &desc_ring->ringcb;

    struct dma_desc  *tdesc = (struct dma_desc *)0;
    /* Lock first */

    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_00();

    if (ring_remain(ring) < cnt) {
        tdesc = NULL_PTR;
    } else {
        tdesc = &desc_ring->desc[ring->rear % ring->size];
        ring->rear += cnt;
    }

    SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_00();

    return tdesc;
}
/**
 * @brief Frees a contiguous block of DMA descriptors in a descriptor ring.
 *
 * This function frees a specified number of contiguous DMA descriptors in the transmit or receive
 * descriptor ring of an Ethernet controller. It updates the ring's front pointer to reflect the newly
 * freed descriptors. The function ensures that the requested number of descriptors is available to be
 * freed before updating the ring state, and it uses critical sections to ensure thread safety when
 * modifying the ring state.
 *
 * @param desc_ring A pointer to the descriptor ring from which to free descriptors.
 * @param cnt The number of descriptors to free.
 *
 * @note The function assumes that the `desc_ring` parameter points to a valid descriptor ring that is
 *       part of an initialized Ethernet controller.
 *
 * @note The function uses the `ring_used` function (or similar) to check if the requested number of
 *       descriptors is available to be freed in the ring.
 *
 * @note The function updates the ring's `front` pointer to reflect the newly freed descriptors. It
 *       wraps around the ring if necessary.
 *
 * @note The function uses critical sections (via `SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_00` and
 *       `SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_00` or similar functions) to ensure thread safety when
 *       accessing and modifying the ring state.
 *
 * @warning The caller must ensure that the `cnt` parameter is a valid number of descriptors and does
 *          not exceed the number of descriptors currently in use in the ring. Attempting to free more
 *          descriptors than are available could lead to undefined behavior.
 */
static void dma_desc_ring_free(dma_desc_ring_t *desc_ring, uint32 cnt)
{
    ring_t *ring = &desc_ring->ringcb;
    /* Lock first */

    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_00();

    if (ring_used(ring) >= cnt) {
        ring->front += cnt;
    }

    SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_00();
}
/*
    DMA DESC ring apis end
*/
/**
 * @brief Allocates a contiguous block of locked descriptors from a locked descriptor ring.
 *
 * This function allocates a specified number of contiguous locked descriptors from the transmit or
 * receive locked descriptor ring of an Ethernet controller. It updates the ring's rear pointer to
 * reflect the newly allocated descriptors. The function ensures that the requested number of
 * descriptors is available before allocating them.
 *
 * @param desc_ring A pointer to the locked descriptor ring from which to allocate descriptors.
 * @param cnt The number of descriptors to allocate.
 *
 * @return A pointer to the first locked descriptor in the allocated block, or `NULL` if the requested
 *         number of descriptors is not available.
 *
 * @note The function assumes that the `desc_ring` parameter points to a valid locked descriptor ring
 *       that is part of an initialized Ethernet controller.
 *
 * @note The function uses the `ring_remain` function (or similar) to check if the requested number of
 *       descriptors is available in the ring.
 *
 * @note The function updates the ring's `rear` pointer to reflect the newly allocated descriptors. It
 *       wraps around the ring if necessary.
 *
 * @warning The caller must ensure that the `cnt` parameter is a valid number of descriptors and does
 *          not exceed the size of the locked descriptor ring. Attempting to allocate more descriptors
 *          than are available could lead to undefined behavior.
 */
static locked_desc_t *locked_desc_ring_alloc(locked_desc_ring_t *desc_ring, uint32 cnt)
{

    ring_t *ring;
    locked_desc_t *locked;
    ring = &desc_ring->ringcb;

    if (ring_remain(ring) < cnt) {
        locked = (locked_desc_t *)0;
    } else {
        locked = &desc_ring->array[ring->rear % ring->size];
        ring->rear += cnt;
    }

    return locked;
}
/**
 * @brief Frees a contiguous block of locked descriptors from a locked descriptor ring and returns the first freed descriptor.
 *
 * This function frees a specified number of contiguous locked descriptors from the transmit or receive
 * locked descriptor ring of an Ethernet controller and returns a pointer to the first freed descriptor.
 * It updates the ring's front pointer to reflect the newly freed descriptors. The function ensures
 * that the requested number of descriptors is available to be freed before updating the ring state,
 * and it uses critical sections to ensure thread safety when modifying the ring state.
 *
 * @param desc_ring A pointer to the locked descriptor ring from which to free descriptors.
 * @param cnt The number of descriptors to free.
 *
 * @return A pointer to the first freed locked descriptor, or `NULL` if the requested number of
 *         descriptors is not available to be freed.
 *
 * @note The function assumes that the `desc_ring` parameter points to a valid locked descriptor ring
 *       that is part of an initialized Ethernet controller.
 *
 * @note The function uses the `ring_used` function (or similar) to check if the requested number of
 *       descriptors is available to be freed in the ring.
 *
 * @note The function updates the ring's `front` pointer to reflect the newly freed descriptors. It
 *       wraps around the ring if necessary.
 *
 * @note The function uses critical sections (via `SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_02` and
 *       `SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_02` or similar functions) to ensure thread safety when
 *       accessing and modifying the ring state.
 *
 * @warning The caller must ensure that the `cnt` parameter is a valid number of descriptors and does
 *          not exceed the number of descriptors currently in use in the ring. Attempting to free more
 *          descriptors than are available could lead to undefined behavior.
 *
 * @warning The returned pointer points to the first freed descriptor and should be used with caution
 *          as the descriptors are now considered free and may be reallocated by subsequent calls to
 *          the `locked_desc_ring_alloc` function.
 */
static locked_desc_t *locked_desc_ring_free(locked_desc_ring_t *desc_ring, \
        uint32 cnt)
{

    ring_t *ring;
    locked_desc_t *locked;
    ring = &desc_ring->ringcb;

    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_02();

    if (ring_used(ring) < cnt) {
        locked = (locked_desc_t *)0;
    } else {
        locked = &desc_ring->array[ring->front % ring->size];
        ring->front += cnt;
    }

    SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_02();

    return locked;
}
/**
 * @brief Retrieves the next locked descriptor from a locked descriptor ring without removing it.
 *
 * This function retrieves the next locked descriptor in the transmit or receive locked descriptor
 * ring of an Ethernet controller, without removing it from the ring. It returns a pointer to the
 * locked descriptor if one is available, or `NULL` if the ring is empty.
 *
 * @param desc_ring A pointer to the locked descriptor ring from which to retrieve the next descriptor.
 *
 * @return A pointer to the next locked descriptor in the ring, or `NULL` if the ring is empty.
 *
 * @note The function assumes that the `desc_ring` parameter points to a valid locked descriptor ring
 *       that is part of an initialized Ethernet controller.
 *
 * @note The function uses the `ring_get_next_index` function (or similar) to retrieve the index of
 *       the next locked descriptor in the ring.
 *
 * @note The retrieved locked descriptor remains in the ring and is not removed by this function.
 *
 * @warning The caller must ensure that the retrieved locked descriptor is not accessed or modified
 *          after it has been removed from the ring by a subsequent call to the
 *          `locked_desc_ring_free` or similar function, to avoid using stale or invalid data.
 */
static locked_desc_t *locked_desc_ring_touch(locked_desc_ring_t *desc_ring)
{
    sint32 index;
    locked_desc_t *locked;
    index = ring_get_next_index(&desc_ring->ringcb);

    if (index != -1) {
        locked = &desc_ring->array[index];
    } else {
        locked = (locked_desc_t *)0;
    }

    return locked;
}
/**
 * @brief Allocates a single DMA descriptor from the specified transmit or receive descriptor ring.
 *
 * This function allocates a single DMA descriptor from the transmit or receive descriptor ring of
 * the specified Ethernet controller and channel. It selects the appropriate descriptor ring based
 * on the `rx` parameter, which indicates whether to allocate from the receive (RX) or transmit (TX)
 * descriptor ring.
 *
 * @param CtrlIdx The index of the Ethernet controller.
 * @param channel The index of the Ethernet channel within the controller.
 * @param rx A boolean value indicating whether to allocate from the receive (RX) or transmit (TX)
 *           descriptor ring. If `true`, allocate from the RX ring; if `false`, allocate from the TX
 *           ring.
 *
 * @return A pointer to the allocated DMA descriptor, or `NULL` if no descriptors are available in
 *         the specified descriptor ring.
 *
 * @note The function assumes that the `Eth_Desc_Buf` array is initialized and contains valid
 *       descriptor rings for each Ethernet controller, channel, and direction (RX/TX).
 *
 * @note The function uses the `dma_desc_ring_alloc` function to allocate the DMA descriptor from the
 *       specified descriptor ring.
 *
 * @warning The caller must ensure that the `CtrlIdx` and `channel` parameters are valid and
 *          correspond to an initialized Ethernet controller and channel.
 *
 * @warning The allocated DMA descriptor must be freed using the appropriate function (e.g.,
 *          `dma_desc_ring_free` or a similar function) once it is no longer needed to avoid memory
 *          leaks.
 */
struct dma_desc *alloc_dma_desc(uint8 CtrlIdx, uint8 channel, boolean rx)
{
    dma_desc_ring_t *desc_ring;

    if (rx) {
        desc_ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_RX];
    } else {
        desc_ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_TX];
    }

    return dma_desc_ring_alloc(desc_ring, 1);
}
/**
 * @description:free dma desc
 * @param {uint8} CtrlIdx
 * @param {boolean} rx
 * @return {*}
 */
void free_dma_desc(uint8 CtrlIdx, uint8 channel, boolean rx)
{
    dma_desc_ring_t *desc_ring;

    if (rx) {
        desc_ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_RX];
    } else {
        desc_ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_TX];
    }

    dma_desc_ring_free(desc_ring, 1);
}
/**
 * @brief Adds a locked descriptor to the specified transmit or receive locked descriptor ring.
 *
 * This function adds a locked descriptor to the transmit or receive locked descriptor ring of the
 * specified Ethernet controller and channel. It selects the appropriate locked descriptor ring
 * based on the `rx` parameter, which indicates whether to add to the receive (RX) or transmit (TX)
 * locked descriptor ring. The locked descriptor's contents are copied to a newly allocated locked
 * descriptor in the ring.
 *
 * @param CtrlIdx The index of the Ethernet controller.
 * @param channel The index of the Ethernet channel within the controller.
 * @param descp A pointer to the locked descriptor to be added to the ring.
 * @param rx A boolean value indicating whether to add to the receive (RX) or transmit (TX) locked
 *           descriptor ring. If `true`, add to the RX locked ring; if `false`, add to the TX locked
 *           ring.
 *
 * @return `0` on success, indicating that the locked descriptor was successfully added to the ring.
 *         `-1` on failure, indicating that no space was available in the specified locked descriptor
 *         ring to add the locked descriptor.
 *
 * @note The function assumes that the `Eth_Buf_Confirm` array is initialized and contains valid
 *       locked descriptor rings for each Ethernet controller, channel, and direction (RX/TX).
 *
 * @note The function uses the `locked_desc_ring_alloc` function to allocate a new locked descriptor
 *       in the specified locked descriptor ring.
 *
 * @note The locked descriptor's contents (`desc`, `buf_idx`, and `confirm` fields) are copied to the
 *       newly allocated locked descriptor in the ring.
 *
 * @warning The caller must ensure that the `CtrlIdx` and `channel` parameters are valid and
 *          correspond to an initialized Ethernet controller and channel.
 *
 * @warning The caller must ensure that the `descp` parameter points to a valid locked descriptor
 *          that is safe to access and copy.
 *
 * @warning The allocated locked descriptor in the ring is now owned by the ring and should not be
 *          modified or freed by the caller.
 */
sint32 locked_desc_put(uint8 CtrlIdx, uint8 channel,
                       locked_desc_t *descp, boolean rx)
{
    locked_desc_t *locked;
    locked_desc_ring_t *locked_ring;

    if (rx) {
        locked_ring = &Eth_Buf_Confirm[CtrlIdx][channel][DESC_RX];
    } else {
        locked_ring = &Eth_Buf_Confirm[CtrlIdx][channel][DESC_TX];
    }

    SchM_Enter_Eth_ETH_EXCLUSIVE_AREA_02();
    locked = locked_desc_ring_alloc(locked_ring, 1);

    if (locked) {
        locked->desc = descp->desc;
        locked->buf_idx = descp->buf_idx;
        locked->confirm = descp->confirm;
        SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_02();
        return 0;
    }

    SchM_Exit_Eth_ETH_EXCLUSIVE_AREA_02();

    return -1;
}
/**
 * @description:pop an item
 * @param {uint8} CtrlIdx
 * @param {locked_desc_t} *
 * @param {boolean} rx
 * @return {*}
 */
sint32 locked_desc_get(uint8 CtrlIdx, uint8 channel,
                       locked_desc_t **descpp, boolean rx)
{
    locked_desc_t *locked;
    locked_desc_ring_t *locked_ring;

    if (rx) {
        locked_ring = &Eth_Buf_Confirm[CtrlIdx][channel][DESC_RX];
    } else {
        locked_ring = &Eth_Buf_Confirm[CtrlIdx][channel][DESC_TX];
    }

    locked = locked_desc_ring_free(locked_ring, 1);

    if (locked) {
        *descpp = locked;
        return 0;
    }

    return -1;
}
/**
 * @description:get specify desc buf addr
 * @param {uint8} CtrlIdx
 * @param {locked_desc_t} *
 * @param {uint16} index
 * @param {boolean} rx
 * @return {*}
 */
sint32 locked_desc_touch(uint8 CtrlIdx, uint8 channel,
                         locked_desc_t **descpp, boolean rx)
{
    locked_desc_t *locked;
    locked_desc_ring_t *locked_ring;

    if (rx) {
        locked_ring = &Eth_Buf_Confirm[CtrlIdx][channel][DESC_RX];
    } else {
        locked_ring = &Eth_Buf_Confirm[CtrlIdx][channel][DESC_TX];
    }

    locked = locked_desc_ring_touch(locked_ring);

    if (locked) {
        *descpp = locked;
        return 0;
    }

    return -1;
}
/**
 * @description:get specify desc buf addr from desc idx
 * @param {uint8} CtrlIdx
 * @param {uint32} index
 * @param {boolean} is_rx
 * @return {*dma_desc}
 */
struct dma_desc *get_dma_desc(uint8 CtrlIdx,
                              uint8 channel, uint32 curidx, boolean rx)
{
    dma_desc_ring_t *ring;

    if (rx) {
        ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_RX];
    } else {
        ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_TX];
    }

    return &ring->desc[curidx];
}
/**
 * @description:get specify desc next desc buf addr from desc idx
 * @param {uint8} CtrlIdx
 * @param {uint32} index
 * @param {boolean} is_rx
 * @return {*dma_desc}
 */
struct dma_desc *get_dma_desc_next(uint8 CtrlIdx,
                                   uint8 channel, uint32 curidx, boolean rx)
{
    uint32 next = curidx + 1;
    dma_desc_ring_t *ring;

    if (rx) {
        ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_RX];
    } else {
        ring = &Eth_Desc_Buf[CtrlIdx][channel][DESC_TX];
    }

    if (next >= MAX_ETH_RING_LENTH) {
        next = 0;
    }

    return &ring->desc[next];
}
/*
    exported api end
*/

#define ETH_STOP_SEC_CODE_FAST
#include "Eth_MemMap.h"

#ifdef __cplusplus
}
#endif
